﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using MMessaging.Address;
using MMessaging.Address.Services;
using MMessaging.MessagingEx.Common;

namespace MMessaging.WPF
{
	public class MMessagingClient4WPF : IDisposable
	{
		public MAddress ClientAddress { get; private set; }
		public MAddress[] Roles { get; private set; }
		private const int INTERVAL_TIME_ALIFE_MESSAGE = 2000;
		private ClientService _clientService;
		private Dispatcher _dispatcher;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="clientLoggingName">
		/// just for logging purpose
		/// </param>
		/// <param name="dispatcher">
		/// dispatcher that should run the message handler
		/// </param>
		/// <param name="switchNode">
		/// the switch, to which this client should be connected to.
		/// </param>
		/// <param name="activateLoggingMessageProtocoll">
		/// true, if logging via logging message protocoll
		/// </param>
		/// <param name="messageHandlerOnServiceThread">
		/// message handler running on client service thread.
		/// May be null.
		/// </param>
		/// <param name="roles"></param>
		/// <param name="messageHandlerOnWPFThread">
		/// message handler running on dispatcher thread.
		/// Note ! in this handler you haven't access to Wait-Methods.
		/// May be null.
		/// </param>
		public MMessagingClient4WPF(
			string clientLoggingName,
			Dispatcher dispatcher,
			IMNodeDuplex<MAddressMessageBase> switchNode,
			Action<MAddressMessageBase> messageHandlerOnWPFThread,
			Action<IMTask<MAddressMessageBase>, Action<Action>> messageHandlerOnServiceThread,
			params string[] roles)
		{
			_dispatcher = dispatcher;
			ClientAddress = new MAddress(clientLoggingName + Guid.NewGuid().ToString());
			Roles = roles.Select(r => new MAddress(r)).ToArray();
			_clientService = new ClientService(
				dispatcher,
				ClientAddress,
				messageHandlerOnWPFThread,
				messageHandlerOnServiceThread,
				Roles);
			_clientService.Init(
				loggingNameOfService: clientLoggingName,
				node: switchNode,
				maxCountOfThreads: 3,
				startAtOnce: true);
		}


		private class ClientService : MAddressServiceBase
		{
			private Action<MAddressMessageBase> _messageHandler;
			private Action<IMTask<MAddressMessageBase>, Action<Action>> _messageHandlerOnServiceThread;
			private Dispatcher _dispatcher;
			public ClientService(
				Dispatcher dispatcher,
				MAddress clientAddress,
				Action<MAddressMessageBase> messageHandler,
				Action<IMTask<MAddressMessageBase>, Action<Action>> messageHandlerOnServiceThread,
				params MAddress[] roles)
				: base(
					serviceAddress: clientAddress,
					intervallTimeAlifeMessage:INTERVAL_TIME_ALIFE_MESSAGE,
					roles:roles)
			{
				_messageHandlerOnServiceThread = messageHandlerOnServiceThread;
				_dispatcher = dispatcher;
				_messageHandler = messageHandler;
			}

			protected override void OnMessage(IMTask<MAddressMessageBase> context)
			{
				if (_messageHandler != null && context.OriginalMessage != null)
				{
					var handler = _messageHandler;
					var message = context.OriginalMessage;
					_dispatcher.BeginInvoke((Action) (() => handler(message)));
				}

				if (_messageHandlerOnServiceThread != null)
				{
					_messageHandlerOnServiceThread(
						context,
						action => _dispatcher.Invoke(action));
				}
			}
		}

		public void PostMessage(MAddressMessageBase message)
		{
			if ( _clientService != null )
				_clientService.PostMessage(message);
		}

		public void Dispose()
		{
			if (_clientService != null)
			{
				_clientService.CancelAsync();
				_clientService = null;
			}
		}
	}
}
